/*
** Copyright (C) 2010 Calin Radoni
**
** This file is part of CHScanner.
**
** CHScanner is free software: you can redistribute it and/or modify
** it under the terms of the GNU General Public License as published by
** the Free Software Foundation, either version 3 of the License, or
** (at your option) any later version.
**
** CHScanner is distributed in the hope that it will be useful,
** but WITHOUT ANY WARRANTY; without even the implied warranty of
** MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
** GNU General Public License for more details.
**
** You should have received a copy of the GNU General Public License
** along with CHScanner. If not, see <http://www.gnu.org/licenses/>.
*/

#include "StdAfx.h"
#include "PacketBuilderDhcp.h"

#include <Winsock2.h>

//---------------------------------------------------------------------------

PacketBuilderDhcp::PacketBuilderDhcp(void)
{
}

PacketBuilderDhcp::~PacketBuilderDhcp(void)
{
}

//---------------------------------------------------------------------------

int PacketBuilderDhcp::DhcpAddMagicCookie(BYTE* buff)
{
	buff[0] = 0x63;
	buff[1] = 0x82;
	buff[2] = 0x53;
	buff[3] = 0x63;

	return 4;
}

int PacketBuilderDhcp::DhcpAddOption51(BYTE* buff, DWORD leaseTimeIn)
{
	BYTE* bbb;

	bbb = (BYTE*)&leaseTimeIn;

	buff[0] = 0x33;
	buff[1] = 0x04;
	buff[2] = bbb[3];
	buff[3] = bbb[2];
	buff[4] = bbb[1];
	buff[5] = bbb[0];

	return 6;
}

int PacketBuilderDhcp::DhcpAddOption53(BYTE* buff, BYTE msgType)
{
	buff[0] = 0x35;
	buff[1] = 0x01;
	buff[2] = msgType;

	return 3;
}

int PacketBuilderDhcp::DhcpAddOption57(BYTE* buff)
{
	buff[0] = 0x39;
	buff[1] = 0x02;
	buff[2] = 0x05;
	buff[3] = 0xC0;

	return 4;
}

int PacketBuilderDhcp::DhcpAddOption116(BYTE* buff)
{
	buff[0] = 0x74;
	buff[1] = 0x01;
	buff[2] = 0x01;

	return 3;
}

int PacketBuilderDhcp::DhcpAddOption61(BYTE* buff, BYTE* srcMacIn)
{
	buff[0] = 0x3D;
	buff[1] = 0x07;
	buff[2] = 0x01;
	buff[3] = srcMacIn[0];
	buff[4] = srcMacIn[1];
	buff[5] = srcMacIn[2];
	buff[6] = srcMacIn[3];
	buff[7] = srcMacIn[4];
	buff[8] = srcMacIn[5];

	return 9;
}

int PacketBuilderDhcp::DhcpAddOption50(BYTE* buff, DWORD reqIpIn)
{
	in_addr ia;

	ia.S_un.S_addr = reqIpIn;
	buff[0] = 0x32;
	buff[1] = 0x04;
	buff[2] = ia.S_un.S_un_b.s_b1;
	buff[3] = ia.S_un.S_un_b.s_b2;
	buff[4] = ia.S_un.S_un_b.s_b3;
	buff[5] = ia.S_un.S_un_b.s_b4;

	return 6;
}

int PacketBuilderDhcp::DhcpAddOption54(BYTE* buff, DWORD srvIpIn)
{
	in_addr ia;

	ia.S_un.S_addr = srvIpIn;
	buff[0] = 0x36;
	buff[1] = 0x04;
	buff[2] = ia.S_un.S_un_b.s_b1;
	buff[3] = ia.S_un.S_un_b.s_b2;
	buff[4] = ia.S_un.S_un_b.s_b3;
	buff[5] = ia.S_un.S_un_b.s_b4;

	return 6;
}

int PacketBuilderDhcp::DhcpAddOption12(BYTE* buff, CString srcNameIn)
{
	int i, idx, nameSize;

	/*
		About the size of HostName:

		A. The size of HostName is reprezented on 1 byte, this means the maximum allowed is 255
		B. The max size of options field (without extending) is 312. Usage is:
			- 26 before the Hostname
			- 11 for option 60 (MICROSOFT CASE !!!)
			- 13 for option 55
			- 1  for end of options
		   which leaves 261 for HostName.

		In conclusion, restraining the HostName to 255 should be enough.
	*/

	nameSize = srcNameIn.GetLength();
	if(nameSize>255) return false;

	idx = 0;
	buff[idx++] = 0x0C;
	buff[idx++] = (BYTE)nameSize;
	for(i=0; i<nameSize; i++){
		buff[idx] = srcNameIn[i];
		idx++;
	}

	return idx;
}

int PacketBuilderDhcp::DhcpAddOption81(BYTE* buff, CString srcNameIn)
{
	int i, idx, nameSize;

	nameSize = srcNameIn.GetLength();
	if(nameSize>255) return false;

	idx = 0;
	buff[idx++] = 0x51;
	buff[idx++] = (BYTE)(nameSize+4);
	buff[idx++] = 0x00;	// flags
	buff[idx++] = 0x00;	// a-rr
	buff[idx++] = 0x00;	// ptr-rr
	for(i=0; i<nameSize; i++){
		buff[idx] = srcNameIn[i];
		idx++;
	}
	buff[idx++] = 0x2e;	// '.'

	return idx;
}

int PacketBuilderDhcp::DhcpAddOption60XP(BYTE* buff)
{
	buff[0] = 0x3C;
	buff[1] = 0x08;
	buff[2] = 0x4D;	// 'M'
	buff[3] = 0x53;	// 'S'
	buff[4] = 0x46;	// 'F'
	buff[5] = 0x54;	// 'T'
	buff[6] = 0x20;	// ' '
	buff[7] = 0x35;	// '5'
	buff[8] = 0x2E;	// '.'
	buff[9] = 0x30;	// '0'

	return 10;
}

int PacketBuilderDhcp::DhcpAddOption602K3(BYTE* buff)
{
	buff[0] = 0x3C;
	buff[1] = 0x08;
	buff[2] = 0x4D;	// 'M'
	buff[3] = 0x53;	// 'S'
	buff[4] = 0x46;	// 'F'
	buff[5] = 0x54;	// 'T'
	buff[6] = 0x20;	// ' '
	buff[7] = 0x35;	// '5'
	buff[8] = 0x2E;	// '.'
	buff[9] = 0x31;	// '1'

	return 10;
}

int PacketBuilderDhcp::DhcpAddOption60Nevada35(BYTE* buff)
{
	buff[0]  = 0x3C;
	buff[1]  = 0x0A;
	buff[2]  = 0x53; // 'S'
	buff[3]  = 0x55; // 'U'
	buff[4]  = 0x4e; // 'N'
	buff[5]  = 0x57; // 'W'
	buff[6]  = 0x2e; // '.'
	buff[7]  = 0x69; // 'i'
	buff[8]  = 0x38; // '8'
	buff[9]  = 0x36; // '6'
	buff[10] = 0x70; // 'p'
	buff[11] = 0x63; // 'c'

	return 12;
}

int PacketBuilderDhcp::DhcpAddOption55XP(BYTE* buff)
{
	buff[0]  = 0x37;
	buff[1]  = 0x0B;
	buff[2]  = 0x01;	// Subnet Mask
	buff[3]  = 0x0F;	// Domain Name
	buff[4]  = 0x03;	// Router
	buff[5]  = 0x06;	// Domain Name Server
	buff[6]  = 0x2C;	// NetBIOS over TCP/IP Name Server
	buff[7]  = 0x2E;	// NetBIOS over TCP/IP Node Type
	buff[8]  = 0x2F;	// NetBIOS over TCP/IP Scope
	buff[9]  = 0x1F;	// Perform Router Discover
	buff[10] = 0x21;	// Static Route
	buff[11] = 0xF9;	// ???
	buff[12] = 0x2B;	// Vendor-Specific Information

	return 13;
}

int PacketBuilderDhcp::DhcpAddOption55_2_4(BYTE* buff)
{
	buff[0] = 0x37;
	buff[1] = 0x07;
	buff[2] = 0x01;	// Subnet Mask
	buff[3] = 0x1C;	// Broadcast Address
	buff[4] = 0x02;	// Time Offest
	buff[5] = 0x03;	// Router
	buff[6] = 0x0F;	// Domain Name
	buff[7] = 0x06;	// Domain Name Server
	buff[8] = 0x0C;	// Host Name

	return 9;
}

int PacketBuilderDhcp::DhcpAddOption55_2_6(BYTE* buff)
{
	buff[0]  = 0x37;
	buff[1]  = 0x0A;
	buff[2]  = 0x01;	// Subnet Mask
	buff[3]  = 0x1C;	// Broadcast Address
	buff[4]  = 0x02;	// Time Offest
	buff[5]  = 0x03;	// Router
	buff[6]  = 0x0F;	// Domain Name
	buff[7]  = 0x06;	// Domain Name Server
	buff[8]  = 0x0C;	// Host Name
	buff[9]  = 0x28;	// Network Information Service Domain
	buff[10] = 0x29;	// Network Information Service Servers
	buff[11] = 0x2A;	// Network Time Protocol Servers

	return 12;
}

int PacketBuilderDhcp::DhcpAddOption55Nevada35(BYTE* buff)
{
	buff[0] = 0x37;
	buff[1] = 0x07;
	buff[2] = 0x01;		// Subnet Mask
	buff[3] = 0x03;		// Router
	buff[4] = 0x06;		// Domain Name Server
	buff[5] = 0x0C;		// Host Name
	buff[6] = 0x0F;		// Domain Name
	buff[7] = 0x1C;		// Broadcast Address
	buff[8] = 0x2B;		// Vendor-Specific Information

	return 9;
}

//---------------------------------------------------------------------------

int PacketBuilderDhcp::DhcpAddDiscoverOptionsXP(BYTE* buff, BYTE* srcMacIn, DWORD reqIpIn, CString srcNameIn)
{
	int idx;

	idx = 0;
	idx += DhcpAddMagicCookie(&buff[idx]);				// magic cookie
	idx += DhcpAddOption53(&buff[idx], 0x01);			// Option 53: message type = DHCP Discover
	idx += DhcpAddOption116(&buff[idx]);				// Option 116: DHCP autoconf
	idx += DhcpAddOption61(&buff[idx], srcMacIn);		// Option 61: Client ID
	idx += DhcpAddOption50(&buff[idx], reqIpIn);		// option 50: Requested IP
	idx += DhcpAddOption12(&buff[idx], srcNameIn);		// option 12: Host Name
	idx += DhcpAddOption60XP(&buff[idx]);				// option 60: Vendor Class Id
	idx += DhcpAddOption55XP(&buff[idx]);				// option 55: Parameter Request List
	buff[idx++] = 0xFF;									// option FF: End

	return idx;
}

int PacketBuilderDhcp::DhcpAddRequestOptionsXP(BYTE* buff, BYTE* srcMacIn, DWORD srvIpIn, DWORD reqIpIn, CString srcNameIn, DWORD leaseTimeIn)
{
	int idx;

	idx = 0;
	idx += DhcpAddMagicCookie(&buff[idx]);				// magic cookie
	idx += DhcpAddOption53(&buff[idx], 0x03);			// Option 53: message type = DHCP Request
	idx += DhcpAddOption61(&buff[idx], srcMacIn);		// Option 61: Client ID
	idx += DhcpAddOption50(&buff[idx], reqIpIn);		// option 50: Requested IP
	idx += DhcpAddOption54(&buff[idx], srvIpIn);		// option 54: Server Identifier
	idx += DhcpAddOption12(&buff[idx], srcNameIn);		// option 12: Host Name
	idx += DhcpAddOption81(&buff[idx], srcNameIn);		// option 81: FQDN
	idx += DhcpAddOption60XP(&buff[idx]);				// option 60: Vendor Class Id
	idx += DhcpAddOption55XP(&buff[idx]);				// option 55: Parameter Request List
	buff[idx++] = 0xFF;									// option FF: End

	return idx;
}

//---------------------------------------------------------------------------

int PacketBuilderDhcp::DhcpAddDiscoverOptions2K3(BYTE* buff, BYTE* srcMacIn, DWORD reqIpIn, CString srcNameIn)
{
	int idx;

	idx = 0;
	idx += DhcpAddMagicCookie(&buff[idx]);				// magic cookie
	idx += DhcpAddOption53(&buff[idx], 0x01);			// Option 53: message type = DHCP Discover
	idx += DhcpAddOption116(&buff[idx]);				// Option 116: DHCP autoconf
	idx += DhcpAddOption61(&buff[idx], srcMacIn);		// Option 61: Client ID
	idx += DhcpAddOption50(&buff[idx], reqIpIn);		// option 50: Requested IP
	idx += DhcpAddOption12(&buff[idx], srcNameIn);		// option 12: Host Name
	idx += DhcpAddOption602K3(&buff[idx]);				// option 60: Vendor Class Id
	idx += DhcpAddOption55XP(&buff[idx]);				// option 55: Parameter Request List
	buff[idx++] = 0xFF;									// option FF: End

	return idx;
}

int PacketBuilderDhcp::DhcpAddRequestOptions2K3(BYTE* buff, BYTE* srcMacIn, DWORD srvIpIn, DWORD reqIpIn, CString srcNameIn, DWORD leaseTimeIn)
{
	int idx;

	idx = 0;
	idx += DhcpAddMagicCookie(&buff[idx]);				// magic cookie
	idx += DhcpAddOption53(&buff[idx], 0x03);			// Option 53: message type = DHCP Request
	idx += DhcpAddOption61(&buff[idx], srcMacIn);		// Option 61: Client ID
	idx += DhcpAddOption50(&buff[idx], reqIpIn);		// option 50: Requested IP
	idx += DhcpAddOption54(&buff[idx], srvIpIn);		// option 54: Server Identifier
	idx += DhcpAddOption12(&buff[idx], srcNameIn);		// option 12: Host Name
	idx += DhcpAddOption81(&buff[idx], srcNameIn);		// option 81: FQDN
	idx += DhcpAddOption602K3(&buff[idx]);				// option 60: Vendor Class Id
	idx += DhcpAddOption55XP(&buff[idx]);				// option 55: Parameter Request List
	buff[idx++] = 0xFF;									// option FF: End

	return idx;
}

//---------------------------------------------------------------------------

int PacketBuilderDhcp::DhcpAddDiscoverOptions2_4(BYTE* buff, BYTE* srcMacIn, DWORD reqIpIn, CString srcNameIn)
{
	int idx;

	idx = 0;
	idx += DhcpAddMagicCookie(&buff[idx]);				// magic cookie
	idx += DhcpAddOption53(&buff[idx], 0x01);			// Option 53: message type = DHCP Discover
	idx += DhcpAddOption55_2_4(&buff[idx]);				// option 55: Parameter Request List
	buff[idx++] = 0xFF;									// option FF: End

	return idx;
}

int PacketBuilderDhcp::DhcpAddRequestOptions2_4(BYTE* buff, BYTE* srcMacIn, DWORD srvIpIn, DWORD reqIpIn, CString srcNameIn, DWORD leaseTimeIn)
{
	int idx;

	idx = 0;
	idx += DhcpAddMagicCookie(&buff[idx]);				// magic cookie
	idx += DhcpAddOption53(&buff[idx], 0x03);			// Option 53: message type = DHCP Request
	idx += DhcpAddOption54(&buff[idx], srvIpIn);		// option 54: Server Identifier
	idx += DhcpAddOption50(&buff[idx], reqIpIn);		// option 50: Requested IP
	idx += DhcpAddOption55_2_4(&buff[idx]);				// option 55: Parameter Request List
	buff[idx++] = 0xFF;									// option FF: End

	return idx;
}

//---------------------------------------------------------------------------

int PacketBuilderDhcp::DhcpAddDiscoverOptions2_6(BYTE* buff, BYTE* srcMacIn, DWORD reqIpIn, CString srcNameIn)
{
	int idx;

	idx = 0;
	idx += DhcpAddMagicCookie(&buff[idx]);				// magic cookie
	idx += DhcpAddOption53(&buff[idx], 0x01);			// Option 53: message type = DHCP Discover
	idx += DhcpAddOption55_2_6(&buff[idx]);				// option 55: Parameter Request List
	buff[idx++] = 0xFF;									// option FF: End

	return idx;
}

int PacketBuilderDhcp::DhcpAddRequestOptions2_6(BYTE* buff, BYTE* srcMacIn, DWORD srvIpIn, DWORD reqIpIn, CString srcNameIn, DWORD leaseTimeIn)
{
	int idx;

	idx = 0;
	idx += DhcpAddMagicCookie(&buff[idx]);				// magic cookie
	idx += DhcpAddOption53(&buff[idx], 0x03);			// Option 53: message type = DHCP Request
	idx += DhcpAddOption54(&buff[idx], srvIpIn);		// option 54: Server Identifier
	idx += DhcpAddOption50(&buff[idx], reqIpIn);		// option 50: Requested IP
	idx += DhcpAddOption55_2_6(&buff[idx]);				// option 55: Parameter Request List
	buff[idx++] = 0xFF;									// option FF: End

	return idx;
}

//---------------------------------------------------------------------------

int PacketBuilderDhcp::DhcpAddDiscoverOptionsNevada35(BYTE* buff, BYTE* srcMacIn, DWORD reqIpIn, CString srcNameIn)
{
	int idx;

	idx = 0;
	idx += DhcpAddMagicCookie(&buff[idx]);				// magic cookie
	idx += DhcpAddOption53(&buff[idx], 0x01);			// Option 53: message type = DHCP Discover
	idx += DhcpAddOption57(&buff[idx]);					// Option 57: Maximum DHCP Message Size
	idx += DhcpAddOption51(&buff[idx], 0xFFFFFFFF);		// Option 51: IP Address Lease Time
	idx += DhcpAddOption60Nevada35(&buff[idx]);			// option 60: Vendor Class Id
	idx += DhcpAddOption55Nevada35(&buff[idx]);			// option 55: Parameter Request List
	buff[idx++] = 0xFF;									// option FF: End

	return idx;
}

int PacketBuilderDhcp::DhcpAddRequestOptionsNevada35(BYTE* buff, BYTE* srcMacIn, DWORD srvIpIn, DWORD reqIpIn, CString srcNameIn, DWORD leaseTimeIn)
{
	int idx;

	idx = 0;
	idx += DhcpAddMagicCookie(&buff[idx]);				// magic cookie
	idx += DhcpAddOption53(&buff[idx], 0x03);			// Option 53: message type = DHCP Request
	idx += DhcpAddOption51(&buff[idx], leaseTimeIn);	// Option 51: IP Address Lease Time
	idx += DhcpAddOption57(&buff[idx]);					// Option 57: Maximum DHCP Message Size
	idx += DhcpAddOption50(&buff[idx], reqIpIn);		// option 50: Requested IP
	idx += DhcpAddOption54(&buff[idx], srvIpIn);		// option 54: Server Identifier
	idx += DhcpAddOption60Nevada35(&buff[idx]);			// option 60: Vendor Class Id
	idx += DhcpAddOption55Nevada35(&buff[idx]);			// option 55: Parameter Request List
	buff[idx++] = 0xFF;									// option FF: End

	return idx;
}

//---------------------------------------------------------------------------

int PacketBuilderDhcp::DhcpAddDiscoverOptions(MimicOS mimicIn, BYTE* buff, BYTE* srcMacIn, DWORD reqIpIn, CString srcNameIn)
{
	int idx;

	if(buff==NULL || srcMacIn==NULL) return 9999;

	switch(mimicIn){
		case __mosRandom :
			idx = DhcpAddDiscoverOptions2_4(buff, srcMacIn, reqIpIn, srcNameIn);
			break;

		case __mosWindowsXPSP2 :
			idx = DhcpAddDiscoverOptionsXP(buff, srcMacIn, reqIpIn, srcNameIn);
			break;

		case __mosWindows2K3 :
			idx = DhcpAddDiscoverOptions2K3(buff, srcMacIn, reqIpIn, srcNameIn);
			break;

		case __mosLinux_2_4:
			idx = DhcpAddDiscoverOptions2_4(buff, srcMacIn, reqIpIn, srcNameIn);
			break;

		case __mosLinux_2_6:
			idx = DhcpAddDiscoverOptions2_6(buff, srcMacIn, reqIpIn, srcNameIn);
			break;

		case __mosSolaris_8:
			idx = 9999;
			break;

		case __mosNevada35 :
			idx = DhcpAddDiscoverOptionsNevada35(buff, srcMacIn, reqIpIn, srcNameIn);
			break;

		default:
			idx = 9999;
			break;
	}

	return idx;
}

int PacketBuilderDhcp::DhcpAddRequestOptions(
		MimicOS mimicIn, BYTE* buff, BYTE* srcMacIn, DWORD srvIpIn, DWORD reqIpIn, CString srcNameIn, DWORD leaseTimeIn
	)
{
	int idx;

	if(buff==NULL || srcMacIn==NULL) return 9999;

	switch(mimicIn){
		case __mosRandom :
			idx = DhcpAddRequestOptions2_4(buff, srcMacIn, srvIpIn, reqIpIn, srcNameIn, leaseTimeIn);
			break;

		case __mosWindowsXPSP2 :
			idx = DhcpAddRequestOptionsXP(buff, srcMacIn, srvIpIn, reqIpIn, srcNameIn, leaseTimeIn);
			break;

		case __mosWindows2K3 :
			idx = DhcpAddRequestOptions2K3(buff, srcMacIn, srvIpIn, reqIpIn, srcNameIn, leaseTimeIn);
			break;

		case __mosLinux_2_4:
			idx = DhcpAddRequestOptions2_4(buff, srcMacIn, srvIpIn, reqIpIn, srcNameIn, leaseTimeIn);
			break;

		case __mosLinux_2_6:
			idx = DhcpAddRequestOptions2_6(buff, srcMacIn, srvIpIn, reqIpIn, srcNameIn, leaseTimeIn);
			break;

		case __mosSolaris_8:
			idx = 9999;
			break;

		case __mosNevada35 :
			idx = DhcpAddRequestOptionsNevada35(buff, srcMacIn, srvIpIn, reqIpIn, srcNameIn, leaseTimeIn);
			break;

		default:
			idx = 9999;
			break;
	}

	return idx;
}

//---------------------------------------------------------------------------
